package com.settlement.system.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.settlement.system.common.base.IBaseEnum;
import com.settlement.system.common.constant.SystemConstants;
import com.settlement.system.common.enums.*;
import com.settlement.system.common.model.Option;
import com.settlement.system.common.util.DateUtils;
import com.settlement.system.common.util.SecurityUtils;
import com.settlement.system.common.util.StringUtils;
import com.settlement.system.mapper.*;
import com.settlement.system.mapper.security.userdetails.SysUserDetails;
import com.settlement.system.model.entity.*;
import com.settlement.system.model.query.*;
import com.settlement.system.model.vo.*;
import com.settlement.system.rules.RuleChecker;
import com.settlement.system.service.*;
import lombok.RequiredArgsConstructor;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * <p>
 * 标准核销表 服务实现类
 * </p>
 *
 * @author huangrensen
 * @since 2023-08-05
 */
@Service
@RequiredArgsConstructor
public class SysAuditServiceImpl extends ServiceImpl<SysAuditMapper, SysAudit> implements SysAuditService {

    private final Logger logger = LoggerFactory.getLogger(SysAuditServiceImpl.class);

    private final RedissonClient redissonClient;

    private final SysCompanyService sysCompanyService;

    private final SysDictService sysDictService;

    private final SysBillService sysBillService;

    private final SysOrderService sysOrderService;

    private final SysAuditRuleService auditRuleService;

    private final SysFileAuditMapper sysFileAuditMapper;

    private final SysRoleService roleService;

    private final SysDoneAuditService doneAuditService;

    private final SysAuditCheckInMapper sysAuditCheckInMapper;

    private final SysAuditNoLinkMapper auditNoLinkMapper;

    private final SysOrderMapper sysOrderMapper;

    private final SysBillMapper sysBillMapper;

    private final SysStoreService storeService;

    private final SysSubjectsService sysSubjectsService;

    private final SysPlatformService sysPlatformService;

    private final SysOrderDetailMapper orderDetailMapper;

    private final SysDoneAuditNoLinkService doneAuditNoLinkService;

    private final BsOmsOrderMapper bsOmsOrderMapper;

    private final SnowflakeIdWorker snowflakeIdWorker = SnowflakeIdWorker.getInstance();

    private final LinkNoHistoryMapper linkNoHistoryMapper;

    private final RedisTemplate redisTemplate;

    private final AuditErrorRecordService auditErrorRecordService;


    @Value("${rule.other.id}")
    private String ruleOtherId;

    @Value("${system.config.expire}")
    private Integer expire;

    @Value("${rule.trace.id}")
    private String traceRuleId;

    @Override
    public Page<SysAudit> getAuditPage(AuditPageQuery queryParams) {
        List<RoleVO> roleList = roleService.listAll();
        // 查询参数
        int pageNum = queryParams.getPageNum();
        int pageSize = queryParams.getPageSize();
        String keywords = queryParams.getKeywords();
        SysUserDetails user = SecurityUtils.getUser();
        LocalDateTime startDate = null;
        LocalDateTime endDate = null;
        if (queryParams.getStartDate() != null && queryParams.getEndDate() != null) {
            startDate = queryParams.getStartDate().atStartOfDay();
            endDate = queryParams.getEndDate().plusDays(1).atStartOfDay();
        }
        boolean isManager;
        if(Objects.nonNull(user)){
            isManager = AuditManagerEnum.YES.getValue().equals(user.getManager());
        }else{
            // 多线程运行时，用户信息获取不到，所以临时放在变量里使用
            isManager = queryParams.isManager();
            logger.info("正在使用多线程查询{}页，isManager【{}】...", pageNum, isManager);
        }
        LambdaQueryWrapper<SysAudit> query = new LambdaQueryWrapper<SysAudit>()
                .likeRight(StrUtil.isNotBlank(keywords), SysAudit::getOrderNo, keywords)
                .eq(StrUtil.isNotBlank(queryParams.getSecordSourceCode()), SysAudit::getSecordSourceCode, queryParams.getSecordSourceCode())
                .eq(StrUtil.isNotBlank(queryParams.getThirdSourceCode()), SysAudit::getThirdSourceCode, queryParams.getThirdSourceCode())
                .eq(StrUtil.isNotBlank(queryParams.getShopCode()), SysAudit::getShopCode, queryParams.getShopCode())
                .eq(StrUtil.isNotBlank(queryParams.getBillSysStore()), SysAudit::getBillSysStore, queryParams.getBillSysStore())
                .eq(StrUtil.isNotBlank(queryParams.getInnerShopCode()), SysAudit::getInnerShopCode, queryParams.getInnerShopCode())
                .eq(StrUtil.isNotBlank(queryParams.getReceiveCompany()), SysAudit::getReceiveCompany, queryParams.getReceiveCompany())
                .eq(StrUtil.isNotBlank(queryParams.getAuditStatus()), SysAudit::getAuditStatus, queryParams.getAuditStatus())
                .eq(StrUtil.isNotBlank(queryParams.getPush()), SysAudit::getBelongRole, queryParams.getPush())
                .between(startDate != null, SysAudit::getBusinessDate, startDate, endDate)
                .likeRight(StrUtil.isNotBlank(queryParams.getLinkNo()), SysAudit::getLinkNo,
                        queryParams.getLinkNo())
                .eq(StrUtil.isNotBlank(queryParams.getMainTypeName()), SysAudit::getMainTypeName,
                        queryParams.getMainTypeName());
        if (!isManager) {
            if (!SecurityUtils.isRoot()) {
                // 如果不是角色负责人，只能查看manager==0||manager==null的数据
                query.and(qr -> qr.eq(SysAudit::getManager, AuditManagerEnum.NO.getValue()).or().isNull(SysAudit::getManager));
            }
        } else {
            // 如果是角色负责人，可以查看所有数据，并且按照manager排序
            query.orderByDesc(SysAudit::getManager);
        }
        // 按照修改时间倒叙
        query.orderByDesc(SysAudit::getBusinessDate);
        // 查询数据
        Page<SysAudit> auditPage = this.page(new Page<>(pageNum, pageSize), query);
        // 是否核销
        List<Option> options = sysDictService.listDictOptions("hasAudit");
        for (SysAudit record : auditPage.getRecords()) {
            options.stream().filter(option -> option.getValue().equals(record.getAudit()))
                    .findFirst()
                    .ifPresent(option -> record.setAudit(option.getLabel()));
        }
        // 核销结果分类
        options = sysDictService.listDictOptions("jgfl");
        // 入账主体
        List<SysCompany> sysCompanyList = sysCompanyService.list();
        // 订单核销细类名称
        List<SysAuditRule> ruleList = auditRuleService.getAll();
        for (SysAudit record : auditPage.getRecords()) {
            // 入账主体
            sysCompanyList.stream().filter(sysCompany -> Objects.equals(sysCompany.getCode(), record.getReceiveCompany()))
                    .findFirst()
                    .ifPresent(sysCompany -> record.setReceiveCompany(sysCompany.getName()));
            // 核销状态
            roleList.stream().filter(option -> Objects.equals(record.getBelongRole(), option.getCode()))
                    .findFirst()
                    .ifPresent(option -> record.setAuditStatus("待%s处理".formatted(option.getName())));
            // 核销结果分类
            options.stream().filter(option -> Objects.equals(option.getValue(), record.getMainTypeName()))
                    .findFirst()
                    .ifPresent(option -> record.setMainTypeName(option.getLabel()));
            // 订单核销细类名称
            ruleList.stream().filter(rule -> Objects.equals(rule.getRuleCode(), record.getRuleCode()))
                    .findFirst()
                    .ifPresent(rule -> record.setAuditDetailName(rule.getOrderAuditType()));
        }
        return auditPage;
    }

    @Override
    public Page<SysAudit> pageAll(AuditPageQuery queryParams) {
        List<RoleVO> roleList = roleService.listAll();
        // 查询参数
        int pageNum = queryParams.getPageNum();
        int pageSize = queryParams.getPageSize();
        String keywords = queryParams.getKeywords();
        LambdaQueryWrapper<SysAudit> query = new LambdaQueryWrapper<SysAudit>()
                .likeRight(StrUtil.isNotBlank(keywords), SysAudit::getOrderNo, keywords)
                .eq(StrUtil.isNotBlank(queryParams.getSecordSourceCode()), SysAudit::getSecordSourceCode, queryParams.getSecordSourceCode())
                .eq(StrUtil.isNotBlank(queryParams.getThirdSourceCode()), SysAudit::getThirdSourceCode, queryParams.getThirdSourceCode())
                .eq(StrUtil.isNotBlank(queryParams.getShopCode()), SysAudit::getShopCode, queryParams.getShopCode())
                .eq(StrUtil.isNotBlank(queryParams.getBillSysStore()), SysAudit::getBillSysStore, queryParams.getBillSysStore())
                .eq(StrUtil.isNotBlank(queryParams.getInnerShopCode()), SysAudit::getInnerShopCode, queryParams.getInnerShopCode())
                .eq(StrUtil.isNotBlank(queryParams.getReceiveCompany()), SysAudit::getReceiveCompany, queryParams.getReceiveCompany())
                .eq(StrUtil.isNotBlank(queryParams.getAuditStatus()), SysAudit::getAuditStatus, queryParams.getAuditStatus())
                .eq(StrUtil.isNotBlank(queryParams.getPush()), SysAudit::getBelongRole, queryParams.getPush())
                .likeRight(StrUtil.isNotBlank(queryParams.getLinkNo()), SysAudit::getLinkNo,
                        queryParams.getLinkNo())
                .eq(StrUtil.isNotBlank(queryParams.getMainTypeName()), SysAudit::getMainTypeName,
                        queryParams.getMainTypeName());
        // 按照修改时间倒叙
        query.orderByDesc(SysAudit::getBusinessDate);
        // 查询数据
        Page<SysAudit> auditPage = this.page(new Page<>(pageNum, pageSize), query);
        // 是否核销
        List<Option> options = sysDictService.listDictOptions("hasAudit");
        for (SysAudit record : auditPage.getRecords()) {
            options.stream().filter(option -> option.getValue().equals(record.getAudit()))
                    .findFirst()
                    .ifPresent(option -> record.setAudit(option.getLabel()));
        }
        // 核销结果分类
        options = sysDictService.listDictOptions("jgfl");
        for (SysAudit record : auditPage.getRecords()) {
            options.stream().filter(option -> option.getValue().equals(record.getMainTypeName()))
                    .findFirst()
                    .ifPresent(option -> record.setMainTypeName(option.getLabel()));
        }
        // 核销状态
        for (SysAudit record : auditPage.getRecords()) {
            roleList.stream().filter(option -> option.getCode().equals(record.getBelongRole()))
                    .findFirst()
                    .ifPresent(option -> record.setAuditStatus("待%s处理".formatted(option.getName())));
        }
        List<SysCompany> sysCompanyList = sysCompanyService.list();
        for (SysAudit record : auditPage.getRecords()) {
            sysCompanyList.stream().filter(sysCompany -> sysCompany.getCode().equals(record.getReceiveCompany()))
                    .findFirst()
                    .ifPresent(sysCompany -> record.setReceiveCompany(sysCompany.getName()));
        }
        return auditPage;
    }

    @Override
    public AuditVo getAuditForm(String auditId) {
        AuditVo auditVo = new AuditVo();
        SysAudit sysAudit = this.getById(auditId);
        List<RoleVO> roleList = roleService.listAll();
        if (sysAudit != null) {
            BeanUtil.copyProperties(sysAudit, auditVo);
            SysStore sysStore = storeService.getById(sysAudit.getStoreId());
            auditVo.setInnerShopName(sysStore.getInnerSystemStoreName());
            if (StringUtils.hasText(sysAudit.getReceiveCompany())) {
                SysCompany company = sysCompanyService.getCompanyByCode(sysAudit.getReceiveCompany());
                if (company != null) {
                    auditVo.setReceiveCompanyName(company.getName());
                }
            }
            if (CancellationStatusEnum.NO.getValue().equals(sysAudit.getAuditStatus())) {
                auditVo.setAuditStatus(CancellationStatusEnum.NO.getLabel());
            } else {
                auditVo.setAuditStatus(CancellationStatusEnum.YES.getLabel());
            }
            List<Option> options = sysDictService.listDictOptions("jgfl");
            for (Option option : options) {
                if (option.getValue().equals(sysAudit.getMainTypeName())) {
                    auditVo.setMainTypeName(option.getLabel());
                    break;
                }
            }
            // 核销状态
            auditVo.setAuditStatus(null);
            roleList.stream().filter(option -> option.getCode().equals(sysAudit.getBelongRole()))
                    .findFirst()
                    .ifPresent(option -> auditVo.setAuditStatus("待%s处理".formatted(option.getName())));
            // 角色编码
            auditVo.setRoleCode(sysAudit.getBelongRole());
        }
        return auditVo;
    }

    @Override
    public List<SysOrderVO> getOrderList(String linkNo) {
        List<SysOrderVO> sysOrders = new ArrayList<>();
        int lastYear = 2024;
        List<Integer> yearList = new ArrayList<>();
        int year = LocalDate.now().getYear();
        while (year >= lastYear) {
            yearList.add(year);
            year--;
        }
        List<SysAuditNoLink> allAuditNoLinks = new ArrayList<>();
        List<SysAuditNoLink> sysAuditNoLinks;
        SysAuditNoLink query;
        for (Integer yearInt : yearList) {
            query = new SysAuditNoLink();
            query.setTableName("sys_audit_no_link_%s".formatted(yearInt));
            query.setLinkNo(linkNo);
            query.setType(OrderEnum.ORDER.getValue());
            sysAuditNoLinks = auditNoLinkMapper.getList(query);
            if (sysAuditNoLinks.size() > 0) {
                allAuditNoLinks.addAll(sysAuditNoLinks);
            }
        }
        if (allAuditNoLinks.size() == 0) {
            return sysOrders;
        }
        String tableName;
        SysOrder sysOrder;
        List<SysOrder> sysOrderList = new ArrayList<>();
        for (SysAuditNoLink sysAuditNoLink : allAuditNoLinks) {
            tableName = "sys_order_%s".formatted(sysAuditNoLink.getTableId().substring(0, 6));
            sysOrder = sysOrderMapper.getOrderById(tableName, sysAuditNoLink.getTableId());
            if (Objects.nonNull(sysOrder)) {
                sysOrderList.add(sysOrder);
            }
        }
        SysStore sysStore;
        SysPlatform sysPlatform;
        SysOrderVO sysOrderVO;
        for (SysOrder order : sysOrderList) {
            sysOrderVO = new SysOrderVO();
            sysStore = storeService.getById(order.getStoreId());
            sysPlatform = sysPlatformService.getByPlatformKey(order.getPlatform());
            BeanUtil.copyProperties(order, sysOrderVO);
            if (Objects.nonNull(sysStore)) {
                // 电商平台店铺名称
                sysOrderVO.setPlatformStoreName(sysStore.getCommercePlatformStoreName());
                // 对账系统店铺名称
                sysOrderVO.setBillStoreName(sysStore.getBillSystemStoreName());
                // 内部系统电商平台名称
                sysOrderVO.setInnerShopName(sysStore.getInnerSystemCommercePlatformName());
                // 内部系统店铺名称
                sysOrderVO.setShopName(sysStore.getInnerSystemStoreName());
                // 财务系统店铺名称
                sysOrderVO.setBillSysStoreName(sysStore.getFinanceSystemStoreName());
            }
            if (Objects.nonNull(sysPlatform)) {
                // 电商平台名称
                sysOrderVO.setPlatform(sysPlatform.getReconciliationSystemName());
            }
            sysOrders.add(sysOrderVO);
        }
        return sysOrders;
    }

    @Override
    public List<SysOrderDetailVo> getOrderDetailList(String linkNo) {
        int lastYear = 2024;
        List<Integer> yearList = new ArrayList<>();
        int year = LocalDate.now().getYear();
        while (year >= lastYear) {
            yearList.add(year);
            year--;
        }
        List<SysAuditNoLink> allAuditNoLinks = new ArrayList<>();
        List<SysAuditNoLink> sysAuditNoLinks;
        SysAuditNoLink query;
        for (Integer yearInt : yearList) {
            query = new SysAuditNoLink();
            query.setTableName("sys_audit_no_link_%s".formatted(yearInt));
            query.setLinkNo(linkNo);
            query.setType(OrderEnum.ORDER.getValue());
            sysAuditNoLinks = auditNoLinkMapper.getList(query);
            if (sysAuditNoLinks.size() > 0) {
                allAuditNoLinks.addAll(sysAuditNoLinks);
            }
        }
        List<SysOrderDetail> orderDetailList = new ArrayList<>();
        List<SysOrderDetailVo> voList = new ArrayList<>();
        // 先查出关联的ID，通过ID前面6位数字可以知道是属于那个月份的表
        if (allAuditNoLinks.size() == 0) {
            return voList;
        }
        String tableName;
        SysOrder sysOrder;
        List<SysOrder> sysOrderList = new ArrayList<>();
        for (SysAuditNoLink sysAuditNoLink : allAuditNoLinks) {
            tableName = "sys_order_%s".formatted(sysAuditNoLink.getTableId().substring(0, 6));
            sysOrder = sysOrderMapper.getOrderById(tableName, sysAuditNoLink.getTableId());
            if (Objects.nonNull(sysOrder)) {
                if (StringUtils.hasText(sysOrder.getFileAuditId())) {
                    continue;
                }
                sysOrderList.add(sysOrder);
            }
        }
        // 查出核销单记录
        SysAudit sysAudit = this.getOne(new LambdaQueryWrapper<SysAudit>().eq(SysAudit::getLinkNo, linkNo));
        // 根据订单ID查询订单详情
        SysOrderDetail sysOrderDetail;
        List<SysOrderDetail> sysOrderDetails;
        for (SysOrder order : sysOrderList) {
            sysOrderDetail = new SysOrderDetail();
            sysOrderDetail.setSourceMainNo(linkNo);
            sysOrderDetail.setTableName("sys_order_detail_%s".formatted(order.getId().substring(0, 6)));
            sysOrderDetails = orderDetailMapper.getList(sysOrderDetail);
            if (sysOrderDetails.size() > 0) {
                for (SysOrderDetail orderDetail : sysOrderDetails) {
                    if (Objects.equals(orderDetail.getAuditId(), sysAudit.getId())) {
                        orderDetailList.add(orderDetail);
                    }
                }
            }
        }
        SysStore sysStore;
        List<String> billMonthList = new ArrayList<>();
        for (SysOrderDetail orderDetail : orderDetailList) {
            if (!billMonthList.contains(orderDetail.getId().substring(0, 6))) {
                billMonthList.add(orderDetail.getId().substring(0, 6));
            }
        }
        List<String> idList = orderDetailList.stream().map(SysOrderDetail::getLinkId).distinct().toList();
        List<BsOmsOrderDetail> allDetailList = new ArrayList<>();
        BsOmsOrderDetail detailQuery;
        for (String billMonth : billMonthList) {
            detailQuery = new BsOmsOrderDetail();
            detailQuery.setTableName("bs_oms_order_detail_%s".formatted(billMonth));
            detailQuery.setOIdList(idList);
            List<BsOmsOrderDetail> list = bsOmsOrderMapper.getDetailList(detailQuery);
            if (list.size() > 0) {
                allDetailList.addAll(list);
            }
        }
        BsOmsOrderDetail vo;
        SysOrderDetailVo detailVo;
        for (SysOrderDetail orderDetail : orderDetailList) {
            // 填充店铺
            sysStore = storeService.getById(orderDetail.getStoreId());
            if (Objects.nonNull(sysStore)) {
                orderDetail.setStoreName(sysStore.getCommercePlatformStoreName());
            }
            if (Objects.nonNull(orderDetail.getOrderType())) {
                orderDetail.setOrderTypeName(IBaseEnum.getLabelByValue(orderDetail.getOrderType(), OMSOrderTypeEnum.class));
            }
            detailVo = new SysOrderDetailVo();
            BeanUtils.copyProperties(orderDetail, detailVo);
            vo = allDetailList.stream().filter(detail -> Objects.equals(detail.getOId(), orderDetail.getLinkId())).findFirst().orElse(null);
            if (Objects.nonNull(vo)) {
                BeanUtils.copyProperties(vo, detailVo, "id");
            }
            voList.add(detailVo);
        }
        return voList;
    }

    @Override
    public List<SysBillVO> getBillDetail(String linkNo) {
        List<SysBillVO> allBillVOS = new ArrayList<>();
        int lastYear = 2024;
        List<Integer> yearList = new ArrayList<>();
        int year = LocalDate.now().getYear();
        while (year >= lastYear) {
            yearList.add(year);
            year--;
        }
        List<SysAuditNoLink> allAuditNoLinks = new ArrayList<>();
        List<SysAuditNoLink> sysAuditNoLinks;
        SysAuditNoLink query;
        for (Integer yearInt : yearList) {
            query = new SysAuditNoLink();
            query.setTableName("sys_audit_no_link_%s".formatted(yearInt));
            query.setLinkNo(linkNo);
            query.setType(OrderEnum.BILL.getValue());
            sysAuditNoLinks = auditNoLinkMapper.getList(query);
            if (sysAuditNoLinks.size() > 0) {
                allAuditNoLinks.addAll(sysAuditNoLinks);
            }
        }
        if (allAuditNoLinks.size() == 0) {
            return allBillVOS;
        }
        // 查出核销单
        SysAudit sysAudit = this.getOne(new LambdaQueryWrapper<SysAudit>().eq(SysAudit::getLinkNo, linkNo));
        List<SysPlatform> platformList = sysPlatformService.list();
        List<SysCompany> sysCompanyList = sysCompanyService.list();
        // 账单月份
        String tableName;
        List<SysBill> sysBillList;
        List<SysBill> sysOrderList = new ArrayList<>();
        String[] billMonthArray;
        for (SysAuditNoLink sysAuditNoLink : allAuditNoLinks) {
            billMonthArray = sysAuditNoLink.getTableId().split(",");
            for (String billMonth : billMonthArray) {
                if (!StringUtils.hasText(billMonth)) {
                    continue;
                }
                if (billMonth.length() > 6) {
                    // 旧数据兼容处理
                    tableName = "sys_bill_%s".formatted(billMonth.substring(0, 6));
                } else {
                    tableName = "sys_bill_%s".formatted(billMonth);
                }
                if (!StringUtils.hasText(sysBillMapper.existTable(tableName))) {
                    continue;
                }
                sysBillList = sysBillMapper.getBillByLinkNo(tableName, sysAuditNoLink.getLinkNo());
                if (sysBillList.size() > 0) {
                    for (SysBill sysBill : sysBillList) {
                        if ((Objects.equals(sysAudit.getId(), sysBill.getAuditId())) || (!StringUtils.hasText(sysBill.getFileAuditId()) && !StringUtils.hasText(sysBill.getAuditId()))) {
                            sysOrderList.add(sysBill);
                        }
                    }
                }
            }
        }
        SysBillVO vo;
        List<String> codes = new ArrayList<>();
        for (SysBill record : sysOrderList) {
            if (!codes.contains(record.getLastCode())) {
                codes.add(record.getLastCode());
            }
            if (!codes.contains(record.getOtherLastCode())) {
                codes.add(record.getOtherLastCode());
            }
            vo = new SysBillVO();
            BeanUtil.copyProperties(record, vo, "accessory", "otherAccessory");
            if (Objects.isNull(vo.getBillAmount())) {
                vo.setBillAmount(BigDecimal.ZERO);
            }
            if (org.springframework.util.StringUtils.hasText(record.getAccessory())) {
                vo.setAccessory(JSONObject.parseObject(record.getAccessory(), Map.class));
            }
            if (org.springframework.util.StringUtils.hasText(record.getOtherAccessory())) {
                vo.setOtherAccessory(JSONObject.parseObject(record.getOtherAccessory(), Map.class));
            }
            allBillVOS.add(vo);
        }
        List<SysSubjects> sysSubjectsList;
        if (codes.size() == 0) {
            sysSubjectsList = new ArrayList<>();
        } else {
            sysSubjectsList = sysSubjectsService.list(new LambdaQueryWrapper<SysSubjects>().in(SysSubjects::getLastCode, codes));
        }
        for (SysBillVO recordVo : allBillVOS) {
            sysSubjectsList.stream().filter(sysSubjects -> sysSubjects.getLastCode().equals(recordVo.getLastCode()))
                    .findFirst()
                    .ifPresent(sysSubjects -> {
                        recordVo.setLastName(sysSubjects.getLastName());
                        recordVo.setFirstCode(sysSubjects.getFirstCode());
                        recordVo.setFirstName(sysSubjects.getFirstName());
                        recordVo.setBorrowing(sysSubjects.getBorrowing());
                    });
            sysSubjectsList.stream().filter(sysSubjects -> sysSubjects.getLastCode().equals(recordVo.getOtherLastCode()))
                    .findFirst()
                    .ifPresent(sysSubjects -> {
                        recordVo.setOtherLastName(sysSubjects.getLastName());
                        recordVo.setOtherFirstCode(sysSubjects.getFirstCode());
                        recordVo.setOtherFirstName(sysSubjects.getFirstName());
                        recordVo.setOtherBorrowing(sysSubjects.getBorrowing());
                    });
            // 对方账单金额
            recordVo.setOtherBillAmount(recordVo.getBillAmount());
            // 对账系统平台名称
            platformList.stream().filter(platform -> platform.getReconciliationSystemCode().equals(recordVo.getBillSystemPlatformCode()))
                    .findFirst()
                    .ifPresent(platform -> {
                        recordVo.setBillSystemPlatformName(platform.getReconciliationSystemName());
                    });
            // 入账主体
            sysCompanyList.stream().filter(sysCompany -> sysCompany.getCode().equals(recordVo.getCompanyCode()))
                    .findFirst()
                    .ifPresent(sysCompany -> recordVo.setCompanyCode(sysCompany.getName()));
        }
        // 金额从大到小排序
        allBillVOS.sort((o1, o2) -> o2.getBillAmount().compareTo(o1.getBillAmount()));
        return allBillVOS;
    }

    @Override
    public List<SysFileAudit> auditList(List<HistoryAuditQuery> historyAuditQueryList) {
        if (historyAuditQueryList == null) {
            return new ArrayList<>();
        }
        List<SysFileAudit> sysFileAudits = new ArrayList<>();
        List<String> linkNoList = historyAuditQueryList.stream().map(item -> StringUtils.replaceStr(item.getLinkNo(), "T", "")).distinct().toList();
        List<String> tableNameList = new ArrayList<>();
        String tableName;
        int year = 2024;
        int currentYear = LocalDate.now().getYear();
        while (year <= currentYear) {
            tableName = "link_no_history_%s".formatted(currentYear);
            if (StringUtils.hasText(linkNoHistoryMapper.existTable(tableName))) {
                tableNameList.add(tableName);
            }
            currentYear--;
        }
        if (tableNameList.size() == 0) {
            return new ArrayList<>();
        }
        LinkNoHistory query;
        // 获取文件表名前缀
        List<String> fileTableNameSuffixList = new ArrayList<>();
        // 获取归档id
        List<String> fileAuditIdList = new ArrayList<>();
        for (String tName : tableNameList) {
            query = new LinkNoHistory();
            query.setTableName(tName);
            query.setLinkNoList(linkNoList);
            List<LinkNoHistory> historyList = linkNoHistoryMapper.getList(query);
            if (historyList.size() > 0) {
                for (LinkNoHistory linkNoHistory : historyList) {
                    if (!fileTableNameSuffixList.contains(linkNoHistory.getFileId().substring(0, 6))) {
                        fileTableNameSuffixList.add(linkNoHistory.getFileId().substring(0, 6));
                    }
                    fileAuditIdList.add(linkNoHistory.getFileId());
                }
            }
        }
        tableNameList.clear();
        for (String billMonth : fileTableNameSuffixList) {
            tableName = "sys_file_audit_%s".formatted(billMonth);
            if (!tableNameList.contains(tableName)) {
                tableNameList.add(tableName);
            }
        }
        // 根据账单月份和关联单号查询
        FileAuditPageQuery queryParams;
        List<Option> options = sysDictService.listDictOptions("hasAudit");
        for (String tName : tableNameList) {
            queryParams = new FileAuditPageQuery();
            queryParams.setTableName(tName);
            // 通过关联表ID查找数据
            queryParams.setIdList(fileAuditIdList);
            if (StringUtils.hasText(sysFileAuditMapper.existTable(tName))) {
                List<SysFileAudit> list = sysFileAuditMapper.getHistoryList(queryParams);
                for (SysFileAudit audit : list) {
                    // 填充核销中文名称
                    options.stream().filter(option -> option.getValue().equals(audit.getAudit()))
                            .findFirst()
                            .ifPresent(option -> audit.setAudit(option.getLabel()));
                }
                sysFileAudits.addAll(list);
            }
        }
        return sysFileAudits;
    }

    @Override
    public boolean convert(SysOrder sysOrder, SysPlatform platform, SysStore sysStore) {
        // 获取锁对象
        RLock lock = redissonClient.getLock(SystemConstants.AUDIT_LOCK_PREFIX + sysOrder.getLinkNo());
        if (Objects.isNull(expire)) {
            expire = 30;
        }
        try {
            boolean lockResult = lock.tryLock(20, expire, TimeUnit.SECONDS); // 获取锁失败，需要记录失败日志，方便后面重试
            if (lockResult) {
                logger.info("获取锁成功：{}", sysOrder.getLinkNo());
                this.convertOrder(sysOrder, platform, sysStore);
                return true;
            } else {
                logger.error("获取锁超时：{}", sysOrder.getLinkNo());
                // 获取锁超时
                AuditErrorRecord auditErrorRecord = new AuditErrorRecord();
                // 标准订单
                auditErrorRecord.setDataType(AuditErrorRecordTypeEnum.ORDER.getValue());
                auditErrorRecord.setDataId(sysOrder.getId());
                auditErrorRecord.setStoreId(sysStore.getId());
                auditErrorRecord.setRemark("获取锁超时");
                auditErrorRecordService.checkAndSave(auditErrorRecord);
            }
        } catch (Exception e) {
            logger.error("可能是获取锁失败造成的", e);
            // 获取锁超时
            AuditErrorRecord auditErrorRecord = new AuditErrorRecord();
            // 标准订单
            auditErrorRecord.setDataType(AuditErrorRecordTypeEnum.ORDER.getValue());
            auditErrorRecord.setDataId(sysOrder.getId());
            auditErrorRecord.setStoreId(sysStore.getId());
            auditErrorRecord.setRemark("系统异常：%s".formatted(e.getMessage()));
            auditErrorRecordService.checkAndSave(auditErrorRecord);
        }finally {
            if (Objects.nonNull(lock) && lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
        return false;
    }

    private void convertOrder(SysOrder sysOrder, SysPlatform platform, SysStore sysStore){
        SysAudit sysAudit = getOne(new LambdaQueryWrapper<SysAudit>().eq(SysAudit::getLinkNo, sysOrder.getLinkNo()));
        if (Objects.isNull(sysAudit)) {
            sysAudit = new SysAudit();
            sysAudit.setId(snowflakeIdWorker.nextId(DateUtils.formatDate(sysOrder.getBusinessDate())));
            // 从对账平台中异常核销单处理页面中取值，HX-DY-8位日期-7位流水号
            sysAudit.setOrderNo("HX-DY-%s".formatted(DateUtils.getDateString()));
            sysAudit.setPlatform(platform.getPlatformKey());
            sysAudit.setSecordSourceCode(platform.getReconciliationSystemCode());
            sysAudit.setSecordSourceName(platform.getReconciliationSystemName());
            sysAudit.setChannelCode(platform.getInnerSystemCode());
            sysAudit.setChannel(platform.getInnerSystemName());
            sysAudit.setThirdSourceCode(sysStore.getCommercePlatformStoreCode());
            sysAudit.setThirdSourceName(sysStore.getCommercePlatformStoreName());
            sysAudit.setShopCode(sysStore.getInnerSystemStoreCode());
            sysAudit.setShopName(sysStore.getInnerSystemStoreName());
            sysAudit.setBillSysStore(sysStore.getFinanceSystemStoreCode());
            sysAudit.setBillSysStoreName(sysStore.getFinanceSystemStoreName());
            sysAudit.setBillDate(DateUtils.formatDate(sysOrder.getBusinessDate()));
            sysAudit.setStoreId(sysStore.getId());
            sysAudit.setInnerShopCode(platform.getInnerSystemCode());
            sysAudit.setInnerShopName(platform.getInnerSystemName());
            sysAudit.setDzPlatformStoreCode(sysStore.getBillSystemStoreCode());
            sysAudit.setReceiveCompany(sysStore.getCompanyCode());
            // 对应关联字段
            sysAudit.setLinkNo(sysOrder.getLinkNo());
            sysAudit.setBusinessDate(sysOrder.getBusinessDate());
        }
        // 根据关联单号查询中间表，查出所有的关联订单
        int lastYear = 2024;
        List<Integer> yearList = new ArrayList<>();
        int year = LocalDate.now().getYear();
        while (year >= lastYear) {
            yearList.add(year);
            year--;
        }
        List<SysOrder> allOrderList = new ArrayList<>();
        List<SysAuditNoLink> noLinkList = new ArrayList<>();
        SysAuditNoLink query;
        for (Integer yearInt : yearList) {
            query = new SysAuditNoLink();
            query.setTableName("sys_audit_no_link_%s".formatted(yearInt));
            query.setLinkNo(sysOrder.getLinkNo());
            List<SysAuditNoLink> mapperList = auditNoLinkMapper.getList(query);
            if (mapperList.size() > 0) {
                noLinkList.addAll(mapperList.stream().filter(item -> Objects.equals(item.getType(), OrderEnum.ORDER.getValue())).toList());
            }
        }
        List<String> billMonthList = noLinkList.stream().map(item -> item.getTableId().substring(0, 6)).distinct().toList();
        List<String> tableIdList = noLinkList.stream().map(SysAuditNoLink::getTableId).distinct().toList();
        OrderPageQuery pageQuery;
        for (String billMonth : billMonthList) {
            pageQuery = new OrderPageQuery();
            pageQuery.setTableName("sys_order_%s".formatted(billMonth));
            pageQuery.setOrderIdList(tableIdList);
            if (StringUtils.hasText(sysOrderMapper.existTable(pageQuery.getTableName()))) {
                List<SysOrder> sysOrders = sysOrderMapper.getList(pageQuery);
                if (sysOrders.size() > 0) {
                    for (SysOrder order : sysOrders) {
                        if (StringUtils.hasText(order.getFileAuditId())) {
                            continue;
                        }
                        order.setTableName(pageQuery.getTableName());
                        allOrderList.add(order);
                    }
                }
            }
        }
        // 发货数量 统计所有未归档的发货数量
        sysAudit.setQty(allOrderList.stream().mapToInt(SysOrder::getQty).sum());
        // 商品单价
        sysAudit.setPrice(sysOrder.getPrice());
        // 发货金额 统计所有未归档的发货金额
        sysAudit.setSendAmount(allOrderList.stream().map(SysOrder::getSendAmount).reduce(BigDecimal.ZERO, BigDecimal::add));
        int total = 0;
        BigDecimal totalAmount = BigDecimal.ZERO;
        for (SysOrder order : allOrderList) {
            total += Math.abs(order.getReturnQty());
            totalAmount = totalAmount.add(order.getReturnAmount().abs());
        }
        // 退货数量 统计所有未归档的退货数量
        sysAudit.setReturnQty(-total);
        // 退货金额 统计所有未归档的退货金额
        sysAudit.setReturnAmount(totalAmount.negate());
        // 自系统调账数量
        sysAudit.setSystemReconciliationQty(sysOrder.getSystemReconciliationQty());
        // 自系统调账日期
        sysAudit.setSystemReconciliationDate(sysOrder.getSystemReconciliationDate());
        // 自系统调账金额
        sysAudit.setSystemReconciliationDate(sysOrder.getSystemReconciliationDate());
        // 应收账款余额
        sysAudit.sumReceiveBillAmount();
        if (skipAudit(sysAudit)) {
            return;
        }
        // 查出36条核销规则，按照优先级排序
        List<SysAuditRule> ruleList = auditRuleService.getAll();
        RulerCheckResult rulerCheckResult = this.rulerCheck(ruleList, sysAudit);
        // 更新标准订单的核销ID和归档核销单ID
        sysOrderService.updateAuditId(allOrderList, sysAudit.getId(), rulerCheckResult.getFileAuditId());
    }

    private void checkAuditIsNoBill(SysAudit sysAudit) {
        int lastYear = 2024;
        List<Integer> yearList = new ArrayList<>();
        int year = LocalDate.now().getYear();
        while (year >= lastYear) {
            yearList.add(year);
            year--;
        }
        // 查出是否有关联账单的关系
        SysAuditNoLink sysAuditNoLink;
        List<String> billMonthList = new ArrayList<>();
        for (Integer yearInt : yearList) {
            sysAuditNoLink = new SysAuditNoLink();
            String tableName = "sys_audit_no_link_%s".formatted(yearInt);
            sysAuditNoLink.setTableName(tableName);
            sysAuditNoLink.setLinkNo(sysAudit.getLinkNo());
            sysAuditNoLink.setType(OrderEnum.BILL.getValue());
            if (StringUtils.hasText(auditNoLinkMapper.existTable(tableName))) {
                List<SysAuditNoLink> list = auditNoLinkMapper.getList(sysAuditNoLink);
                if (list.size() > 0) {
                    for (SysAuditNoLink auditNoLink : list) {
                        for (String billMonth : auditNoLink.getTableId().split(",")) {
                            if (!billMonthList.contains(billMonth)) {
                                billMonthList.add(billMonth);
                            }
                        }
                    }
                }
            }
        }
        for (String billMonth : billMonthList) {
            BillPageQuery pageQuery = new BillPageQuery();
            pageQuery.setTableName("sys_bill_%s".formatted(billMonth));
            pageQuery.setLinkNo(sysAudit.getLinkNo());
            if (StringUtils.hasText(sysBillMapper.existTable(pageQuery.getTableName()))) {
                List<SysBill> sysBills = sysBillMapper.getList(pageQuery);
                if (sysBills.size() > 0) {
                    // 证明有账单关联
                    sysAudit.setHasRelationBill(true);
                    break;
                }
            }
        }
        // 如果是单边订单（没有关联账单），再检查发货数量是否等于退货数量，如果不等，则核销单继续跟踪
        // 追加条件，发货金额=0，继续跟踪
        if (!sysAudit.isHasRelationBill() && !Objects.equals(Math.abs(sysAudit.getQty()), Math.abs(sysAudit.getReturnQty())) && BigDecimal.ZERO.compareTo(sysAudit.getSendAmount()) == 0) {
            // 设置一个固定的规则编码
            sysAudit.setRuleCode(traceRuleId);
        } else {
            sysAudit.setRuleCode(null);
        }
    }

    // 是否跳过核销
    private boolean skipAudit(SysAudit sysAudit) {
        // 如果发货金额、退货金额、收款金额、退款金额、保证金金额、发货数量、退货数量都等于0，则不生成核销单
        return sysAudit.getSendAmount().compareTo(BigDecimal.ZERO) == 0 && sysAudit.getReturnAmount().compareTo(BigDecimal.ZERO) == 0
                && sysAudit.getReceiveAmount().compareTo(BigDecimal.ZERO) == 0 && sysAudit.getRefundAmount().compareTo(BigDecimal.ZERO) == 0
                && sysAudit.getDepositAmount().compareTo(BigDecimal.ZERO) == 0 && sysAudit.getQty() == 0 && sysAudit.getReturnQty() == 0;
    }

    @Override
    public boolean convert(String linkNo, List<LocalDateTime> businessDateList, SysPlatform platform, SysStore sysStore, boolean needUpdateBusinessDate) {
        // 获取锁对象
        RLock lock = redissonClient.getLock(SystemConstants.AUDIT_LOCK_PREFIX + linkNo);
        if (Objects.isNull(expire)) {
            expire = 30;
        }
        try {
            boolean lockResult = lock.tryLock(20, expire, TimeUnit.SECONDS); // 获取锁失败，需要记录失败日志，方便后面重试
            if (lockResult) {
                logger.info("获取锁成功：{}", linkNo);
                this.convertBill(linkNo, businessDateList, platform, sysStore, needUpdateBusinessDate);
                return true;
            } else {
                logger.error("获取锁超时：{}", linkNo);
                // 获取锁超时
                AuditErrorRecord auditErrorRecord = new AuditErrorRecord();
                // 标准账单
                auditErrorRecord.setDataType(AuditErrorRecordTypeEnum.BILL.getValue());
                auditErrorRecord.setDataId(linkNo);
                auditErrorRecord.setStoreId(sysStore.getId());
                if (businessDateList.size() > 0) {
                    auditErrorRecord.setBusinessDateStr(String.join(",", businessDateList.stream().map(item -> item.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))).toList()));
                }
                if (needUpdateBusinessDate) {
                    auditErrorRecord.setNeedUpdateBusinessDate(1);
                } else {
                    auditErrorRecord.setNeedUpdateBusinessDate(0);
                }
                auditErrorRecord.setRemark("获取锁超时");
                auditErrorRecordService.checkAndSave(auditErrorRecord);
            }
        } catch (Exception e) {
            logger.error("可能是获取锁失败造成的", e);
            // 获取锁超时
            AuditErrorRecord auditErrorRecord = new AuditErrorRecord();
            // 标准账单
            auditErrorRecord.setDataType(AuditErrorRecordTypeEnum.BILL.getValue());
            auditErrorRecord.setDataId(linkNo);
            auditErrorRecord.setStoreId(sysStore.getId());
            if (businessDateList.size() > 0) {
                auditErrorRecord.setBusinessDateStr(String.join(",", businessDateList.stream().map(item -> item.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))).toList()));
            }
            if (needUpdateBusinessDate) {
                auditErrorRecord.setNeedUpdateBusinessDate(1);
            } else {
                auditErrorRecord.setNeedUpdateBusinessDate(0);
            }
            auditErrorRecord.setRemark("系统异常：%s".formatted(e.getMessage()));
            auditErrorRecordService.checkAndSave(auditErrorRecord);
        }finally {
            if (Objects.nonNull(lock) && lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
        return false;
    }

    private void convertBill(String linkNo, List<LocalDateTime> businessDateList, SysPlatform platform, SysStore sysStore, boolean needUpdateBusinessDate) {
        // 先查出所有关联的账单
        BillPageQuery queryParams;
        List<SysBill> sysBills = new ArrayList<>();
        List<SysBill> queryBills;
        List<String> billMonthList = new ArrayList<>();
        int lastYear = 2024;
        List<Integer> yearList = new ArrayList<>();
        int year = LocalDate.now().getYear();
        while (year >= lastYear) {
            yearList.add(year);
            year--;
        }
        List<SysAuditNoLink> allAuditNoLinks = new ArrayList<>();
        List<SysAuditNoLink> sysAuditNoLinks;
        SysAuditNoLink query;
        for (Integer yearInt : yearList) {
            query = new SysAuditNoLink();
            query.setTableName("sys_audit_no_link_%s".formatted(yearInt));
            query.setLinkNo(linkNo);
            query.setType(OrderEnum.BILL.getValue());
            sysAuditNoLinks = auditNoLinkMapper.getList(query);
            if (sysAuditNoLinks.size() > 0) {
                allAuditNoLinks.addAll(sysAuditNoLinks);
            }
        }
        for (SysAuditNoLink allAuditNoLink : allAuditNoLinks) {
            for (String text : allAuditNoLink.getTableId().split(",")) {
                if (StringUtils.hasText(text)) {
                    if (!billMonthList.contains(text)) {
                        billMonthList.add(text);
                    }
                }
            }
        }
        for (String billMonth : billMonthList) {
            String tableName = "sys_bill_%s".formatted(billMonth);
            queryParams = new BillPageQuery();
            queryParams.setLinkNo(linkNo);
            queryParams.setTableName(tableName);
            queryBills = sysBillService.getList(queryParams);
            if (queryBills.size() > 0) {
                queryBills.forEach(item -> item.setTableName(tableName));
                for (SysBill queryBill : queryBills) {
                    if (StringUtils.hasText(queryBill.getFileAuditId())) {
                        continue;
                    }
                    sysBills.add(queryBill);
                }
            }
        }
        LocalDateTime businessDate;
        if (needUpdateBusinessDate) {
            businessDate = businessDateList.get(0);
        } else {
            // 从businessDateList中取得最晚的日期
            businessDate = businessDateList.stream().max(LocalDateTime::compareTo).get();
        }
        // 创建核销单
        SysAudit sysAudit = getOne(new LambdaQueryWrapper<SysAudit>().eq(SysAudit::getLinkNo, linkNo));
        if (sysAudit == null) {
            sysAudit = new SysAudit();
            // 从对账平台中异常核销单处理页面中取值，HX-DY-8位日期-7位流水号
            sysAudit.setOrderNo("HX-DY-%s".formatted(DateUtils.getDateString()));
            // 根据标准账单配置表将原始账单转换成标准账单
            sysAudit.setPlatform(platform.getPlatformKey());
            sysAudit.setSecordSourceCode(platform.getReconciliationSystemCode());
            sysAudit.setSecordSourceName(platform.getReconciliationSystemName());
            sysAudit.setChannelCode(platform.getInnerSystemCode());
            sysAudit.setChannel(platform.getInnerSystemName());
            sysAudit.setThirdSourceCode(sysStore.getCommercePlatformStoreCode());
            sysAudit.setThirdSourceName(sysStore.getCommercePlatformStoreName());
            sysAudit.setShopCode(sysStore.getInnerSystemStoreCode());
            sysAudit.setShopName(sysStore.getInnerSystemStoreName());
            sysAudit.setBillSysStore(sysStore.getFinanceSystemStoreCode());
            sysAudit.setBillSysStoreName(sysStore.getFinanceSystemStoreName());
            sysAudit.setStoreId(sysStore.getId());
            sysAudit.setInnerShopCode(platform.getInnerSystemCode());
            sysAudit.setInnerShopName(platform.getInnerSystemName());
            sysAudit.setDzPlatformStoreCode(sysStore.getBillSystemStoreCode());
            sysAudit.setReceiveCompany(sysStore.getCompanyCode());
            // 关联字段
            sysAudit.setLinkNo(linkNo);
            // 生成ID
            sysAudit.setId(snowflakeIdWorker.nextId(DateUtils.formatDate(businessDate)));
        } else {
            // 置空收款金额、退款金额、保证金退款、结算前退款、结算后退款
            sysAudit.setReceiveAmount(BigDecimal.ZERO);
            sysAudit.setRefundAmount(BigDecimal.ZERO);
            sysAudit.setDepositAmount(BigDecimal.ZERO);
            sysAudit.setRefundsAfterCheckout(BigDecimal.ZERO);
            sysAudit.setRefundsBeforeCheckout(BigDecimal.ZERO);
        }
        // 业务日期
        if (Objects.isNull(sysAudit.getBusinessDate()) || needUpdateBusinessDate) {
            // 以最晚日期为准
            sysAudit.setBusinessDate(businessDate);
            sysAudit.setBillDate(DateUtils.formatDate(businessDate));
        } else if (sysAudit.getBusinessDate().isBefore(businessDate)) {
            // 以最晚日期为准
            sysAudit.setBusinessDate(businessDate);
            sysAudit.setBillDate(DateUtils.formatDate(businessDate));
        }
        // 过滤出归属于当前核销单或者没有核销记录的标准账单
        String auditId = sysAudit.getId();
        sysBills = sysBills.stream().filter(item -> !StringUtils.hasText(item.getAuditId()) || (Objects.equals(auditId, item.getAuditId()))).toList();
        // 遍历标准账单
        for (SysBill sysBill : sysBills) {
            // 收款日期 收款金额
            if ("收款金额".equals(sysBill.getOriginalBillProject())) {
                sysAudit.setReceiveDate(sysBill.getBusinessDate());
                sysAudit.setReceiveAmount(sysAudit.getReceiveAmount().add(sysBill.getBillAmount()));
            }
            // 退款日期 退款金额
            if ("退款金额".equals(sysBill.getOriginalBillProject())) {
                sysAudit.setRefundDate(sysBill.getBusinessDate());
                sysAudit.setRefundAmount(sysAudit.getRefundAmount().abs().add(sysBill.getBillAmount().abs()).abs().negate());
            }
            // 保证金退款金额
            if (StringUtils.hasText(sysBill.getOriginalBillProject()) && Objects.equals(sysBill.getOriginalBillProject(), "保证金退款")) {
                sysAudit.setDepositAmount(sysAudit.getDepositAmount().abs().add(sysBill.getBillAmount().abs()).abs().negate());
            }
            // 结算前退款
            if (StringUtils.hasText(sysBill.getOriginalBillProject()) && Objects.equals(sysBill.getOriginalBillProject(), "结算前退款")) {
                sysAudit.setRefundsBeforeCheckout(sysAudit.getRefundsBeforeCheckout().abs().add(sysBill.getBillAmount().abs()).abs().negate());
            }
            // 结算后退款
            if (StringUtils.hasText(sysBill.getOriginalBillProject()) && Objects.equals(sysBill.getOriginalBillProject(), "结算后退款")) {
                sysAudit.setRefundsAfterCheckout(sysAudit.getRefundsAfterCheckout().abs().add(sysBill.getBillAmount().abs()).abs().negate());
            }
        }
        if (skipAudit(sysAudit)) {
            // 如果发货金额、退货金额、收款金额、退款金额、保证金金额、发货数量、退货数量都等于0，则不生成核销单
            logger.info("核销单号：【%s】发货金额、退货金额、收款金额、退款金额、保证金金额、发货数量、退货数量都等于0，不生成核销单".formatted(sysAudit.getLinkNo()));
            return;
        }
        // 更新账单的核销单ID
        // 应收账款余额
        sysAudit.sumReceiveBillAmount();
        // 查出36条核销规则，按照优先级排序
        List<SysAuditRule> ruleList = auditRuleService.getAll();
        RulerCheckResult rulerCheckResult = this.rulerCheck(ruleList, sysAudit);
        // 更新标准账单的核销单ID和归档核销单ID
        for (SysBill sysBill : sysBills) {
            sysBillService.updateAuditId(sysBill, sysAudit.getId(), rulerCheckResult.getFileAuditId());
        }
    }

    @Override
    public List<SysAuditExportVO> listExportAudits(List<String> ids) {
        List<SysAuditExportVO> exportVOS = new ArrayList<>();
        List<RoleVO> roleList = roleService.listAll();
        List<SysAudit> sysAudits = this.list(new LambdaQueryWrapper<SysAudit>().in(SysAudit::getId, ids));
        for (SysAudit sysAudit : sysAudits) {
            SysAuditExportVO exportVO = new SysAuditExportVO();
            BeanUtil.copyProperties(sysAudit, exportVO);
            roleList.stream().filter(option -> option.getCode().equals(sysAudit.getBelongRole()))
                    .findFirst()
                    .ifPresent(option -> exportVO.setAuditStatus("待%s处理".formatted(option.getName())));
            exportVOS.add(exportVO);
        }
        return exportVOS;
    }

    @Override
    public List<SysAuditExportVO> listExportAudits(AuditPageQuery queryParams) {
        List<SysAuditExportVO> sysAuditExportVOS = new ArrayList<>();
        List<SysAudit> sysAudits = new ArrayList<>();
        List<RoleVO> roleList = roleService.listAll();
        queryParams.setPageSize(200);
        queryParams.setPageNum(1);
        while (true) {
            Page<SysAudit> auditPage = this.getAuditPage(queryParams);
            if (auditPage.getRecords().size() == 0) {
                break;
            }
            sysAudits.addAll(auditPage.getRecords());
            queryParams.setPageNum(queryParams.getPageNum() + 1);
        }
        for (SysAudit sysAudit : sysAudits) {
            SysAuditExportVO vo = new SysAuditExportVO();
            BeanUtil.copyProperties(sysAudit, vo);
            roleList.stream().filter(option -> option.getCode().equals(sysAudit.getBelongRole()))
                    .findFirst()
                    .ifPresent(option -> vo.setAuditStatus("待%s处理".formatted(option.getName())));
            sysAuditExportVOS.add(vo);
        }
        return sysAuditExportVOS;
    }

    @Override
    public long getTotalPage(AuditPageQuery queryParams) {
        Page<SysAudit> auditPage = this.getAuditPage(queryParams);
        return auditPage.getPages();
    }

    @Override
    public List<SysAuditExportVO> queryByPage(AuditPageQuery queryParams) {
        List<SysAuditExportVO> sysAuditExportVOS = new ArrayList<>();
        List<RoleVO> roleList = roleService.listAll();
        Page<SysAudit> auditPage = this.getAuditPage(queryParams);
        if(auditPage.getRecords().size() > 0){
            for (SysAudit sysAudit : auditPage.getRecords()) {
                SysAuditExportVO vo = new SysAuditExportVO();
                BeanUtil.copyProperties(sysAudit, vo);
                roleList.stream().filter(option -> option.getCode().equals(sysAudit.getBelongRole()))
                        .findFirst()
                        .ifPresent(option -> vo.setAuditStatus("待%s处理".formatted(option.getName())));
                sysAuditExportVOS.add(vo);
            }
        }
        return sysAuditExportVOS;
    }

    @Override
    public List<String> reload(List<SysAuditExportVO> vos) {
        List<String> messages = new ArrayList<>();
        if (vos.stream().anyMatch(vo -> !StringUtils.hasText(vo.getOrderNo()))) {
            messages.add("单据编号一列不能为空，请检查");
            return messages;
        }
        // 同一份导入文档，核销单号有重复，弹窗提示“单号重复”，同时不允许该文件导入
        Map<String, List<SysAuditExportVO>> listMap = vos.stream().collect(Collectors.groupingBy(SysAuditExportVO::getOrderNo));
        listMap.forEach((orderNo, dataList) -> {
            if (dataList.size() > 1) {
                messages.add("单据编号【%s】数据有重复，请检查".formatted(orderNo));
            }
        });
        // 导入的核销单号不存在，弹窗提示“单号不存在”，同时不允许该文件导入
        List<SysAudit> sysAudits = this.list(new LambdaQueryWrapper<SysAudit>().in(SysAudit::getOrderNo, vos.stream().map(SysAuditExportVO::getOrderNo).toList()));
        for (SysAuditExportVO vo : vos) {
            if (sysAudits.stream().noneMatch(record -> record.getOrderNo().equals(vo.getOrderNo()))) {
                messages.add("单据编号【%s】不存在，请检查".formatted(vo.getOrderNo()));
            }
        }
        if (messages.size() == 0) {
            // 查出36条核销规则，按照优先级排序
            List<SysAuditRule> ruleList = auditRuleService.getAll();
            ruleList.sort(Comparator.comparing(SysAuditRule::getPriority));
            SysAudit sysAudit;
            // 没有报错，允许导入
            for (SysAuditExportVO vo : vos) {
                sysAudit = sysAudits.stream().filter(audit -> audit.getOrderNo().equals(vo.getOrderNo())).findFirst().orElse(null);
                if (Objects.nonNull(sysAudit)) {
                    if (Objects.nonNull(vo.getReconciliationAmount()) && BigDecimal.ZERO.compareTo(vo.getReconciliationAmount()) != 0) {
                        // 获取锁对象
                        RLock lock = redissonClient.getLock(SystemConstants.AUDIT_LOCK_PREFIX + sysAudit.getLinkNo());
                        if (Objects.isNull(expire)) {
                            expire = 30;
                        }
                        try{
                            boolean lockResult = lock.tryLock(20, expire, TimeUnit.SECONDS); // 获取锁失败，需要记录失败日志，方便后面重试
                            if(lockResult){
                                logger.info("获取锁成功：{}", sysAudit.getLinkNo());
                                this.reloadAudit(sysAudit, vo, ruleList);
                            }else{
                                logger.error("获取锁失败：{}", sysAudit.getLinkNo());
                                // 获取锁超时
                                AuditErrorRecord auditErrorRecord = new AuditErrorRecord();
                                // 标准订单
                                auditErrorRecord.setDataType(AuditErrorRecordTypeEnum.AUDIT.getValue());
                                auditErrorRecord.setDataId(sysAudit.getId());
                                auditErrorRecord.setRemark("获取锁超时");
                                auditErrorRecordService.checkAndSave(auditErrorRecord);
                            }
                        }catch (Exception e){
                            logger.error("可能是获取锁失败造成的", e);
                            AuditErrorRecord auditErrorRecord = new AuditErrorRecord();
                            // 标准订单
                            auditErrorRecord.setDataType(AuditErrorRecordTypeEnum.AUDIT.getValue());
                            auditErrorRecord.setDataId(sysAudit.getId());
                            auditErrorRecord.setRemark("系统异常：%s".formatted(e.getMessage()));
                            auditErrorRecordService.checkAndSave(auditErrorRecord);
                        }finally {
                            if (Objects.nonNull(lock) && lock.isHeldByCurrentThread()) {
                                lock.unlock();
                            }
                        }
                    }else{
                        logger.error("导入的核销单号：【%s】财务调账金额为空，不做处理".formatted(sysAudit.getLinkNo()));
                    }
                }
            }
        }
        return messages;
    }

    private void reloadAudit(SysAudit sysAudit, SysAuditExportVO vo, List<SysAuditRule> ruleList){
        // 判断是否需要生成财务调账金额的标准账单
        if (sysAudit.getReconciliationAmount() != null && BigDecimal.ZERO.compareTo(sysAudit.getReconciliationAmount()) != 0) {
            // 财务调账的标准账单
            SysBill bill = new SysBill();
            bill.setOriginalBillProject(SystemConstants.FINANCE_RE_BILL);
            bill.setBillAmount(sysAudit.getReconciliationAmount());
            // 关联单号
            bill.setLinkNo(sysAudit.getLinkNo());
            bill.setBusinessDate(sysAudit.getBusinessDate());
            bill.setSysBillDate(DateUtils.formatDate(sysAudit.getBusinessDate()));
            bill.setTableName("sys_bill_%s".formatted(DateUtils.formatDate(sysAudit.getBusinessDate())));
            // 保存财务调账
            sysBillService.generateOtherBill(bill, sysAudit.getPlatform(), sysAudit.getStoreId(),
                    0);
        }
        // 导入的财务调账金额数据覆盖更新系统核销单原有数据
        sysAudit.setReconciliationAmount(vo.getReconciliationAmount());
        // 生成一条财务调账记录
        SysAuditCheckIn checkIn = new SysAuditCheckIn();
        checkIn.setOrderNo(sysAudit.getOrderNo());
        // 财务调账类型
        checkIn.setCheckInType(CheckInTypeEnum.BILL.getValue());
        checkIn.setReconciliationAmount(vo.getReconciliationAmount());
        // 当前操作人
        checkIn.setCheckUserId(SecurityUtils.getUserId());
        // 当前操作时间
        checkIn.setCreateTime(LocalDateTime.now());
        checkIn.setOrderStatusName(CommonEnum.DEAL_SUCCESS.getValue());
        // 保存一个登记记录
        sysAuditCheckInMapper.insert(checkIn);
        // 重新计算应收账款余额
        sysAudit.sumReceiveBillAmount();
        // 重新进入核销轮巡（36条）
        RulerCheckResult rulerCheckResult = this.rulerCheck(ruleList, sysAudit);
        // // 判断是否归档
        if (rulerCheckResult.isConfirm()) {
            // 查出所有参与过当前核销单处理的已办核销单归档
            List<SysDoneAudit> sysDoneAuditList = doneAuditService.list(new LambdaQueryWrapper<SysDoneAudit>().eq(SysDoneAudit::getOrderNo, sysAudit.getOrderNo()));
            List<SysDoneAuditNoLink> doneAuditNoLinks = new ArrayList<>();
            SysDoneAuditNoLink doneAuditNoLink;
            for (SysDoneAudit sysDoneAudit : sysDoneAuditList) {
                // 归档状态
                sysDoneAudit.setStatus(DoneAuditStatusEnum.FILE.getValue());
                sysDoneAudit.setOwnerLoss(OwnerLossEnum.YES.getValue());
                sysDoneAudit.setReceiveBillAmount(BigDecimal.ZERO);
                doneAuditService.updateById(sysDoneAudit);
                doneAuditNoLink = new SysDoneAuditNoLink();
                doneAuditNoLink.setDoneId(sysDoneAudit.getId());
                doneAuditNoLink.setAuditId(sysAudit.getId());
                doneAuditNoLinks.add(doneAuditNoLink);
            }
            // 保存个人核销表与待核销对应关系
            try {
                doneAuditNoLinkService.saveBatch(doneAuditNoLinks);
            } catch (Exception ignore) {
            }
            // 判断当前登录人是否已经有记录，有则更新，否则保存一条已办记录
            SysDoneAudit record = doneAuditService.getOne(new LambdaQueryWrapper<SysDoneAudit>()
                    .eq(SysDoneAudit::getCreateBy, SecurityUtils.getUserId())
                    .eq(SysDoneAudit::getOrderNo, sysAudit.getOrderNo()));
            if (record == null) {
                // 新增
                record = new SysDoneAudit();
                record.setId(snowflakeIdWorker.nextId(""));
                BeanUtil.copyProperties(sysAudit, record, "id", "createBy");
            } else {
                // 覆盖
                BeanUtil.copyProperties(sysAudit, record, "id", "createBy");
                record.setUpdateTime(null);
            }
            record.setStatus(DoneAuditStatusEnum.FILE.getValue());
            record.setCreateBy(SecurityUtils.getUserId());
            doneAuditService.saveOrUpdate(record);
        }
    }

    @Override
    public RulerCheckResult rulerCheck(List<SysAuditRule> ruleList, SysAudit sysAudit) {
        RulerCheckResult rulerCheckResult = new RulerCheckResult();
        boolean check = false;
        boolean isConfirm = false;
        for (SysAuditRule sysAuditRule : ruleList) {
            // 遍历36条规则，如果符合其中一条规则，保存一条数据到待审核核销表
            check = RuleChecker.check(sysAuditRule.getRuleCode(), sysAudit, sysAuditRule);
            // 如果是确认状态，则直接删除待审核的记录，后面直接在归档核销表查询
            if (check) {
                if (ResultTypeEnum.CONFIRM.getValue().equals(sysAuditRule.getResultType())) {
                    // 判断是否单边订单，没有关联账单数据
                    this.checkAuditIsNoBill(sysAudit);
                    if (traceRuleId.equals(sysAudit.getRuleCode())) {
                        SysAuditRule traceRuler = ruleList.stream().filter(r -> Objects.equals(traceRuleId, r.getRuleCode())).findFirst().get();
                        // 填充其他属性
                        sysAudit.setRuleCode(traceRuler.getRuleCode());
                        sysAudit.setRuleName(traceRuler.getRuleName());
                        sysAudit.setAuditDetailName(traceRuler.getOrderAuditType());
                        sysAudit.setMainTypeName(traceRuler.getResultType());
                        sysAudit.setBelongRole(traceRuler.getLiability());
                        if(!StringUtils.hasText(sysAudit.getBelongRole())){
                            sysAudit.setBelongRole(" ");
                        }
                        SysAudit record = this.getOne(new LambdaQueryWrapper<SysAudit>().eq(SysAudit::getLinkNo,
                                sysAudit.getLinkNo()));
                        if (record == null) {
                            record = new SysAudit();
                            record.setId(snowflakeIdWorker.nextId(""));
                        }
                        BeanUtils.copyProperties(sysAudit, record);
                        boolean saveOrUpdate = this.saveOrUpdate(record);
                        Assert.isTrue(saveOrUpdate, "提交的数据有异常，请重新导入");
                    } else {
                        // 确认归档
                        isConfirm = true;
                        // 如果时确认状态，根据待审核核销表的关联单号删除待审核数据
                        this.remove(new LambdaQueryWrapper<SysAudit>().eq(SysAudit::getLinkNo, sysAudit.getLinkNo()));
                        // 查询历史数据是否已经存在核销单，不存在则新增
                        FileAuditPageQuery queryParams = new FileAuditPageQuery();
                        queryParams.setTableName("sys_file_audit_%s".formatted(sysAudit.getBillDate()));
                        queryParams.setKeywords(sysAudit.getOrderNo());
                        if (!StringUtils.hasText(sysFileAuditMapper.existTable(queryParams.getTableName()))) {
                            sysFileAuditMapper.createTable(queryParams.getTableName());
                        }
                        // 清空缓存
                        redisTemplate.delete(SystemConstants.FILE_AUDIT_KEY);
                        List<SysFileAudit> fileAuditList = sysFileAuditMapper.getList(queryParams);
                        if (fileAuditList.size() == 0) {
                            // 保存一份归档数据
                            SysFileAudit sysFileAudit = new SysFileAudit();
                            BeanUtil.copyProperties(sysAudit, sysFileAudit, "id");
                            sysFileAudit.setRuleCode(sysAuditRule.getRuleCode());
                            sysFileAudit.setRuleName(sysAuditRule.getRuleName());
                            sysFileAudit.setAuditDetailName(sysAuditRule.getOrderAuditType());
                            sysFileAudit.setMainTypeName(sysAuditRule.getResultType());
                            // 系统归档
                            sysFileAudit.setAuditStatus(FileAuditStatusEnum.RECORD.getLabel());
                            sysFileAudit.setTableName("sys_file_audit_%s".formatted(sysFileAudit.getBillDate()));
                            sysFileAudit.setId(snowflakeIdWorker.nextId(sysFileAudit.getBillDate()));
                            sysFileAuditMapper.insertData(sysFileAudit);
                            rulerCheckResult.setFileAuditId(sysFileAudit.getId());
                            // 保存一份归档ID对应记录
                            int year = LocalDate.now().getYear();
                            String tableName = "link_no_history_%s".formatted(year);
                            if (!StringUtils.hasText(linkNoHistoryMapper.existTable(tableName))) {
                                linkNoHistoryMapper.createTable(tableName);
                            }
                            LinkNoHistory linkNoHistory = new LinkNoHistory();
                            linkNoHistory.setTableName(tableName);
                            linkNoHistory.setLinkNo(sysAudit.getLinkNo());
                            linkNoHistory.setFileId(sysFileAudit.getId());
                            linkNoHistoryMapper.insertData(linkNoHistory);
                        }
                    }
                } else {
                    // 填充其他属性
                    sysAudit.setRuleCode(sysAuditRule.getRuleCode());
                    sysAudit.setRuleName(sysAuditRule.getRuleName());
                    sysAudit.setAuditDetailName(sysAuditRule.getOrderAuditType());
                    sysAudit.setMainTypeName(sysAuditRule.getResultType());
                    sysAudit.setBelongRole(sysAuditRule.getLiability());
                    if(!StringUtils.hasText(sysAudit.getBelongRole())){
                        sysAudit.setBelongRole(" ");
                    }
                    SysAudit record = this.getOne(new LambdaQueryWrapper<SysAudit>().eq(SysAudit::getLinkNo,
                            sysAudit.getLinkNo()));
                    if (record == null) {
                        record = new SysAudit();
                        record.setId(snowflakeIdWorker.nextId(""));
                    }
                    BeanUtils.copyProperties(sysAudit, record);
                    boolean saveOrUpdate = this.saveOrUpdate(record);
                    Assert.isTrue(saveOrUpdate, "提交的数据有异常，请重新导入");
                }
                break;
            }
        }
        if (!check) {
            ruleList.stream().filter(rule -> rule.getRuleCode().equals(ruleOtherId)).findFirst().ifPresent(rule -> {
                sysAudit.setRuleCode(rule.getRuleCode());
                sysAudit.setRuleName(rule.getRuleName());
                sysAudit.setAudit(CancellationEnum.NO.getValue());
                sysAudit.setAuditDetailName(rule.getOrderAuditType());
                sysAudit.setMainTypeName(rule.getResultType());
                sysAudit.setBelongRole(rule.getLiability());
                if(!StringUtils.hasText(sysAudit.getBelongRole())){
                    sysAudit.setBelongRole(" ");
                }
                SysAudit record = this.getOne(new LambdaQueryWrapper<SysAudit>().eq(SysAudit::getLinkNo,
                        sysAudit.getLinkNo()));
                if (record == null) {
                    record = new SysAudit();
                    record.setId(snowflakeIdWorker.nextId(""));
                }
                BeanUtils.copyProperties(sysAudit, record);
                boolean saveOrUpdate = this.saveOrUpdate(record);
                Assert.isTrue(saveOrUpdate, "提交的数据有异常，请重新导入");
            });
        }
        rulerCheckResult.setConfirm(isConfirm);
        return rulerCheckResult;
    }

    @Override
    public boolean reBill(List<String> ids) {
        // 查出36条核销规则，按照优先级排序
        List<SysAuditRule> ruleList = auditRuleService.getAll();
        ruleList.sort(Comparator.comparing(SysAuditRule::getPriority));
        List<SysAudit> sysAudits = this.list(new LambdaQueryWrapper<SysAudit>().in(SysAudit::getId, ids));
        boolean isSuccess = false;
        for (SysAudit sysAudit : sysAudits) {
            // 获取锁对象
            RLock lock = redissonClient.getLock(SystemConstants.AUDIT_LOCK_PREFIX + sysAudit.getLinkNo());
            if (Objects.isNull(expire)) {
                expire = 30;
            }
            try {
                boolean lockResult = lock.tryLock(20, expire, TimeUnit.SECONDS); // 获取锁失败，需要记录失败日志，方便后面重试
                if (lockResult) {
                    logger.info("获取锁成功：{}", sysAudit.getLinkNo());
                    sysAudit.sumReceiveBillAmount();
                    // 重新进入核销逻辑判断
                    this.rulerCheck(ruleList, sysAudit);
                    isSuccess = true;
                } else {
                    logger.error("获取锁超时：{}", sysAudit.getLinkNo());
                    // 获取锁超时
                    AuditErrorRecord auditErrorRecord = new AuditErrorRecord();
                    // 标准订单
                    auditErrorRecord.setDataType(AuditErrorRecordTypeEnum.AUDIT.getValue());
                    auditErrorRecord.setDataId(sysAudit.getId());
                    auditErrorRecord.setRemark("获取锁超时");
                    auditErrorRecordService.checkAndSave(auditErrorRecord);
                }
            } catch (Exception e) {
                isSuccess = false;
                logger.error("可能是获取锁失败造成的", e);
                // 获取锁超时
                AuditErrorRecord auditErrorRecord = new AuditErrorRecord();
                // 标准订单
                auditErrorRecord.setDataType(AuditErrorRecordTypeEnum.AUDIT.getValue());
                auditErrorRecord.setDataId(sysAudit.getId());
                auditErrorRecord.setRemark("系统异常：%s".formatted(e.getMessage()));
                auditErrorRecordService.checkAndSave(auditErrorRecord);
            }finally {
                if (Objects.nonNull(lock) && lock.isHeldByCurrentThread()) {
                    lock.unlock();
                }
            }
        }
        return isSuccess;
    }

    @Override
    public int deleteByMonth(String month) {
        return this.baseMapper.deleteByMonth(month);
    }
}
